use anyhow::Result;
use git2::{Repository, Signature, DiffOptions};
use tokio::task;

use std::time::{Duration, SystemTime};
use chrono::{DateTime, Local};

/// 提交信息结构体
#[derive(Debug, Clone)]
pub struct CommitInfo {
    pub id: String,
    pub message: String,
    pub author: String,
    pub time: String,
}

/// 获取分支的提交历史
pub async fn get_branch_commits(branch_name: &str) -> Result<Vec<CommitInfo>> {
    let branch_name = branch_name.to_string();

    task::spawn_blocking(move || {
        let repo = Repository::open(".")?;
        let branch = repo.find_branch(&branch_name, git2::BranchType::Local)?;
        let branch_ref = branch.get();

        // 获取分支的最新提交
        let commit_id = branch_ref.target().ok_or_else(||
            anyhow::anyhow!("Invalid branch reference"))?;

        let mut commit = repo.find_commit(commit_id)?;
        let mut commits = Vec::new();

        // 遍历提交历史
        let mut i = 0;
        while i < 100 { // 限制提交数量，避免历史过长
            let commit_info = CommitInfo {
                id: commit.id().to_string(),
                message: commit.message().unwrap_or("").to_string(),
                author: commit.author().name().unwrap_or("Unknown").to_string(),
                time: format_git_time(&commit.time()),
            };

            commits.push(commit_info);

            // 获取父提交
            if commit.parent_count() == 0 {
                break;
            }

            commit = commit.parent(0)?;
            i += 1;
        }

        Ok(commits)
    })
    .await?
}

// 辅助函数：格式化 git2::Time 为字符串
pub fn format_git_time(time: &git2::Time) -> String {
    // 获取时间戳和时区偏移
    let seconds = time.seconds();
    let offset_mins = time.offset_minutes();

    // 计算时区偏移的小时和分钟
    let offset_hours = offset_mins / 60;
    let offset_mins_remainder = offset_mins % 60;

    // 转换为系统时间
    match SystemTime::UNIX_EPOCH.checked_add(Duration::from_secs(seconds as u64)) {
        Some(system_time) => {
            // 转换为本地时间
            let dt: DateTime<Local> = system_time.into();
            // 格式化为人类可读的字符串，包含时区
            format!("{} {:+03}:{:02}",
                dt.format("%Y-%m-%d %H:%M:%S"),
                offset_hours,
                offset_mins_remainder.abs()
            )
        },
        None => "Invalid date".to_string(),
    }
}

/// 获取提交的diff信息
pub async fn get_commit_diff(commit_id: &str) -> Result<String> {
    let commit_id = commit_id.to_string();

    task::spawn_blocking(move || {
        let repo = Repository::open(".")?;
        let commit = repo.find_commit(git2::Oid::from_str(&commit_id)?)?;

        let mut opts = DiffOptions::new();
        opts.context_lines(3); // 标准的上下文行数

        let diff_result = if commit.parent_count() == 0 {
            // 初始提交，比较与空树
            let tree = commit.tree()?;
            repo.diff_tree_to_tree(None, Some(&tree), Some(&mut opts))
        } else {
            // 比较与父提交
            let parent = commit.parent(0)?;
            let parent_tree = parent.tree()?;
            let commit_tree = commit.tree()?;
            repo.diff_tree_to_tree(Some(&parent_tree), Some(&commit_tree), Some(&mut opts))
        };

        let mut diff = diff_result?;
        diff.find_similar(None)?; // 查找重命名和复制

        let mut buf = Vec::new();
        diff.print(git2::DiffFormat::Patch, |_delta, _hunk, line| {
            // 获取行前缀字符 (+, -, ' ') 并转换为字节切片
            let prefix_char = line.origin();
            buf.extend_from_slice(&[prefix_char as u8]);

            buf.extend_from_slice(line.content());
            true
        })?;
        Ok(String::from_utf8(buf)?)
    }).await?
}

/// 创建新提交
pub async fn create_commit(message: &str, author_name: &str, author_email: &str) -> Result<String> {
    let message = message.to_string();
    let author_name = author_name.to_string();
    let author_email = author_email.to_string();

    task::spawn_blocking(move || {
        let repo = Repository::open(".")?;
        let signature = Signature::now(&author_name, &author_email)?;

        // 获取索引
        let mut index = repo.index()?;
        let tree_id = index.write_tree()?;
        let tree = repo.find_tree(tree_id)?;

        // 获取父提交
        let head = repo.head()?;
        let parent_commit = repo.find_commit(
            head.target().ok_or_else(|| anyhow::anyhow!("Invalid HEAD reference"))?
        )?;

        // 创建提交
        let commit_id = repo.commit(
            Some("HEAD"),
            &signature,
            &signature,
            &message,
            &tree,
            &[&parent_commit],
        )?;

        Ok(commit_id.to_string())
    })
    .await?
}
